package cn.cloud9.chinese.taiwan.util;

import cn.cloud9.chinese.taiwan.po.TaiwanRegionPO;
import cn.hutool.core.net.URLEncodeUtil;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import lombok.SneakyThrows;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

import static cn.cloud9.chinese.taiwan.constant.TaiwanPostConstant.REGEXP;
import static cn.cloud9.chinese.taiwan.constant.TaiwanPostConstant.REGEXP2;

/**
 * @projectName: 行政区域爬取工具
 * @author: 戴知舟
 * @date: 2022年07月14日 16:51
 * @version: 1.0
 */
public class TaiwanRegionUtil {

    private static final Db db = Db.use();

    @SneakyThrows
    private static void writeToDB(TaiwanRegionPO po) {
        db.insert(
            Entity.create("`taiwan-region`")
            .set("CODE", po.getCode())
            .set("PARENT_CODE", po.getParentCode())
            .set("FULL_PATH", po.getFullPath())
            .set("NAME", po.getName())
            .set("LEVEL", po.getLevel())
            .set("POST_CODE", po.getPostCode())
            .set("LINK", po.getLink())
            .set("GEN_TIME", LocalDateTime.now())
        );
    }


    public static void getCityData() {
        String html = HttpUtil.get("https://www.youbianku.com/%E5%8F%B0%E6%B9%BE");
        Document postDoc = Jsoup.parse(html);
        Elements cityOptList = postDoc.select("#city > option");
        cityOptList.remove(0);
        cityOptList.forEach(cityOpt -> {
            String cityName = cityOpt.text();
            final String encodeUrl = URLEncodeUtil.encode("https://twn.youbianku.com/city-area-json-new/" + cityName);
            // https://twn.youbianku.com/area-jsons-new/%E5%98%89%E7%BE%A9%E5%B8%82/%E6%9D%B1%E5%8D%80
            TaiwanRegionPO cityPo = TaiwanRegionPO.builder()
                    .code( String.valueOf(cityOptList.indexOf(cityOpt) + 101))
                    .parentCode("0")
                    .name(cityName)
                    .fullPath(cityName)
                    .level(1)
                    .link(encodeUrl)
                    .build();
            writeToDB(cityPo);
            getCountyData(cityPo);
        });

    }

    /**
     *
     * @param po
     */
    private static void getCountyData(TaiwanRegionPO po) {
        final List<String> countyList = packageJsonData(HttpUtil.get(po.getLink()));
        countyList.forEach(countyName -> {
            TaiwanRegionPO countyPo = TaiwanRegionPO.builder()
                    .code(po.getCode() + returnFixDecimal(countyList.indexOf(countyName) + 1))
                    .parentCode(po.getCode())
                    .name(countyName)
                    .fullPath(po.getFullPath() + " -> " + countyName)
                    .level(2)
                    .link("https://twn.youbianku.com/area-jsons-new/" + URLEncodeUtil.encode(po.getName() + "/" + countyName))
                    .build();
            writeToDB(countyPo);
            getRoadData(countyPo);
        });
    }

    /**
     *
     * @param po
     */
    private static void getRoadData(TaiwanRegionPO po) {
        final String json = HttpUtil.get(po.getLink());
        final Matcher matcher = REGEXP2.matcher(json);
        if (!matcher.find()) return;
        String jsonArray = UnicodeUtil.toString(
            matcher.group()
            .replace("{\"node\":{", "{")
            .replace("}}", "}"));
        final List<Map> maps = JSON.parseArray(jsonArray, Map.class);
        maps.forEach(map -> {
            final String address = map.get("Address").toString();
            final String postCode = map.get("Postcode3 3").toString();
            writeToDB(TaiwanRegionPO.builder()
                .code(po.getCode() + returnFixDecimal2(maps.indexOf(map) + 1))
                .parentCode(po.getCode())
                .postCode(postCode)
                .name(address)
                .fullPath(po.getFullPath() + " -> " + address)
                .level(3)
                .build());
        });
    }

    private static String returnFixDecimal(Integer idx) {
        return 10 > idx ? "00" + idx :  "0" + idx;
    }
    private static String returnFixDecimal2(Integer idx) {
        if (10 > idx) return "000" + idx;
        else if (100 > idx) return "00" + idx;
        else if (1000 > idx) return "0" + idx;
        return idx.toString();
    }

    /**
     *
     * @param jsonResult
     * @return
     */
    public static List<String> packageJsonData(String jsonResult) {
        final Matcher matcher = REGEXP.matcher(UnicodeUtil.toString(jsonResult));
        final StringBuilder builder = new StringBuilder();
        while (matcher.find()) builder.append(matcher.group());
        return Arrays.asList(builder.toString().split(","));
    }


}
